#pragma once

#include "internal/sdeque.h"

namespace mdtx::punch
{
    template <class QT>
    class BaseDepth
    {
    public:
        using id_type = typename QT::id_type;
        using quant_type = typename QT::quant_type;

        struct level_type
        {
            quant_type price, quant;

            struct BidComparator
            {
                bool operator()(const level_type &lhs, const level_type &rhs) const
                {
                    return lhs.price > rhs.price;
                }

                static bool better_price(quant_type lhs, quant_type rhs)
                {
                    return lhs > rhs;
                }
            };

            struct AskComparator
            {
                bool operator()(const level_type &lhs, const level_type &rhs) const
                {
                    return lhs.price < rhs.price;
                }

                static bool better_price(quant_type lhs, quant_type rhs)
                {
                    return lhs < rhs;
                }
            };
        };

        using bid_depth_type = internal::sdeque<level_type, typename level_type::BidComparator>;
        using ask_depth_type = internal::sdeque<level_type, typename level_type::AskComparator>;

        /**
         * @brief Get bid depth
         *
         * @param ins_id instrument id
         * @return bid_depth_type&
         */
        virtual bid_depth_type &bid(id_type ins_id) = 0;

        /**
         * @brief Get bid depth
         *
         * @param ins_id instrument id
         * @return const bid_depth_type&
         */
        virtual const bid_depth_type &bid(id_type ins_id) const = 0;

        /**
         * @brief Get ask depth
         *
         * @param ins_id instrument id
         * @return ask_depth_type&
         */
        virtual ask_depth_type &ask(id_type ins_id) = 0;

        /**
         * @brief Get ask depth
         *
         * @param ins_id instrument id
         * @return const ask_depth_type&
         */
        virtual const ask_depth_type &ask(id_type ins_id) const = 0;

        /**
         * @brief Callback on trades
         *
         * @param ins_id instrument id
         * @param price traded price
         * @param quant traded quantity
         * @param buy is aggressor a buy order
         */
        virtual void on_trade(id_type ins_id, quant_type price, quant_type quant, bool buy) {}

        /**
         * @brief Callback on updates to depth queues
         *
         * @param ins_id instrument id
         * @param bbo is BBO price changed
         */
        virtual void on_update(id_type ins_id, bool bbo) {}

        virtual ~BaseDepth() = default;
    };
}
